#pragma once

#include<hiredis/hiredis.h>
#include<memory>
#include<string>
#include<atomic>
#include<mutex>

#define CAMPUS_REDIS_URL "127.0.0.1"
#define CAMPUS_REDIS_PORT 6379

#define CAMPUS_REDIS_TIMEOUT_MS 1000

enum CampusRedisStatus
{
    CAMPUS_REDIS_CONNECTED,
    CAMPUS_REDIS_DISCONNECTED,
    CAMPUS_REDIS_ERROR
};

struct RedisContextDeleter
{
    void operator()(redisContext* ctx)
    {
        if (ctx)
        {
            redisFree(ctx);
            ctx = nullptr;
        }
    }
};

struct RedisReplyDeleter
{
    void operator()(redisReply* reply)
    {
        if (reply)
        {
            freeReplyObject(reply);
            reply = nullptr;
        }
    }
};

class CampusRedisConnector{
public:
    CampusRedisConnector(std::string const& redis_url = CAMPUS_REDIS_URL,
        int redis_port = CAMPUS_REDIS_PORT,int timeout_ms = CAMPUS_REDIS_TIMEOUT_MS);
    
        virtual ~CampusRedisConnector();

    // 禁止拷贝构造和赋值操作
    CampusRedisConnector(const CampusRedisConnector&) = delete;
    CampusRedisConnector& operator=(const CampusRedisConnector&) = delete;

    int init();
    int connect();
    int disconnect();

    CampusRedisStatus getStatus() const;
    

protected:
    void setError(std::string const& error);

    std::string get(std::string const& key);
    int set(std::string const& key,std::string const& value,int expire_seconds = 0);
    int exists(std::string const& key);
    int del(std::string const& key);
    int expire(std::string const& key,int seconds);

private:
    std::shared_ptr<redisReply> exec(const char* format, ...);

private:
    std::unique_ptr<redisContext, RedisContextDeleter> redis_context_ = nullptr;
    std::string redis_url_;
    int redis_port_;
    std::string last_error_;
    CampusRedisStatus redis_status_;
    struct timeval timeout_;
    
    std::atomic_bool is_connected_ = { false };
    std::mutex mutex_;

};